from __future__ import annotations

from fastapi import HTTPException, status

from ..models.lead import Lead
from ..models.enums import LeadStage
from ..models.lead_contact import LeadContact
from ..models.lead_note import LeadNote
from ..repositories.lead_repository import LeadRepository
from ..repositories.lead_contact_repository import LeadContactRepository
from ..repositories.lead_note_repository import LeadNoteRepository
from ..repositories.lead_ai_summary_repository import LeadAISummaryRepository
from ..schemas.lead import LeadCreate, LeadUpdate
from ..schemas.lead_contact import LeadContactCreate, LeadContactUpdate
from ..schemas.lead_note import LeadNoteCreate, LeadNoteUpdate


class LeadService:
    def __init__(
        self,
        lead_repo: LeadRepository,
        contact_repo: LeadContactRepository,
        note_repo: LeadNoteRepository,
        ai_repo: LeadAISummaryRepository,
    ) -> None:
        self.lead_repo = lead_repo
        self.contact_repo = contact_repo
        self.note_repo = note_repo
        self.ai_repo = ai_repo

    def create_lead(self, obj_in: LeadCreate) -> Lead:
        if self._has_duplicates(obj_in):
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail="Lead already exists for company/contact",
            )
        return self.lead_repo.create(obj_in)

    def update_lead(self, lead_id: int, obj_in: LeadUpdate) -> Lead | None:
        lead = self.lead_repo.get(lead_id)
        if lead is None:
            return None
        if obj_in.stage is not None and not self._is_valid_stage_transition(
            lead.stage, obj_in.stage
        ):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid stage transition"
            )
        return self.lead_repo.update(lead, obj_in)

    def get_lead(self, lead_id: int) -> Lead | None:
        return self.lead_repo.get_with_relations(lead_id)

    def list_leads(
        self,
        stage: LeadStage | None = None,
        owner_id: int | None = None,
        skip: int = 0,
        limit: int = 50,
    ) -> list[Lead]:
        return self.lead_repo.filter_by_criteria(
            stage=stage, owner_id=owner_id, skip=skip, limit=limit
        )

    def add_contact(self, obj_in: LeadContactCreate) -> LeadContact:
        """添加客户联系人."""
        return self.contact_repo.create(obj_in)

    def update_contact(self, contact_id: int, obj_in: LeadContactUpdate) -> LeadContact | None:
        """更新客户联系人."""
        contact = self.contact_repo.get(contact_id)
        if contact is None:
            return None
        return self.contact_repo.update(contact, obj_in)

    def add_note(self, obj_in: LeadNoteCreate) -> LeadNote:
        """添加客户跟进记录."""
        return self.note_repo.create(obj_in)

    def update_note(self, note_id: int, obj_in: LeadNoteUpdate) -> LeadNote | None:
        """更新客户跟进记录."""
        note = self.note_repo.get(note_id)
        if note is None:
            return None
        return self.note_repo.update(note, obj_in)

    def update_stage(self, lead_id: int, stage: LeadStage) -> Lead | None:
        lead = self.lead_repo.get(lead_id)
        if lead is None:
            return None
        if not self._is_valid_stage_transition(lead.stage, stage):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid stage transition"
            )
        return self.lead_repo.update(lead, {"stage": stage})

    def _has_duplicates(self, obj_in: LeadCreate) -> bool:
        """检查是否存在重复客户（基于手机号）."""
        return self.lead_repo.exists_by_phone(obj_in.phone)

    @staticmethod
    def _is_valid_stage_transition(current: LeadStage, target: LeadStage) -> bool:
        if current == target:
            return True
        transitions: dict[LeadStage, set[LeadStage]] = {
            LeadStage.NEW: {LeadStage.CONTACTED, LeadStage.VIEWING},
            LeadStage.CONTACTED: {LeadStage.VIEWING, LeadStage.NEGOTIATING, LeadStage.CLOSED_LOST},
            LeadStage.VIEWING: {LeadStage.NEGOTIATING, LeadStage.CLOSED_LOST},
            LeadStage.NEGOTIATING: {LeadStage.CLOSED_WON, LeadStage.CLOSED_LOST},
            LeadStage.CLOSED_WON: set(),
            LeadStage.CLOSED_LOST: set(),
        }
        return target in transitions[current]
